import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosError, type AxiosResponse } from "axios";
import { ElLoading } from "element-plus";
import { get, merge } from "lodash";
import awaitTo from "await-to-js";
import { toast, ss } from "@/utils";

let mapLoadingInstance = {};

/**
 * showSuccess: 是否显示成功信息
 */
type MyConfig = {
  /**
   * 接口调用异常，是否使用默认提示方案
   * 1. false 不使用默认方案，接口自行处理
   * 2. true ， 使用默认方案，显示时长 3秒
   * 3. number， 使用默认方案，显示时长为传入的 number
   */
  showError?: boolean | number;
  /**
   * 接口调用成功后，是否显示成功信息
   * 1. false 不提示
   * 2. true：提示 “操作成功”
   * 3. 传入字符串，提示内容变更为 传入的字符串
   */
  showSuccess?: boolean | string;
  /**
   * 接口调用过程中，是否显示 loading
   * 1. true 显示范围整个body
   * 2. false 不显示
   * 3. css 选择器
   * 4. html 元素
   * 5. btn#btnSubmit 按钮
   */
  showLoading?: boolean | string | HTMLElement;
  /** showLoading提示文本 */
  showLoadingText?: string;
  /** loading实例id，无需传入，程序计算获得 */
  loadingId?: string;
};
type DownloadByUrlParams = {
  /** 文件下载地址 */
  fileUrl: string;
  /** 文件名称 */
  fileName?: string;
  /** 文件后缀名 */
  suffixName?: string;
};
type MyAxiosRequestConfig = AxiosRequestConfig & MyConfig;

type MyAxiosResponse = AxiosResponse & MyConfig;

/** 退出登录并强制刷新页面（会重定向到登录页） */
function logout() {
  toast.error("会话超时，请重新登录");
}

const hideLoading = (config = { showLoading: true } as any) => {
  if (mapLoadingInstance[config.loadingId]) {
    mapLoadingInstance[config.loadingId].close();
    delete mapLoadingInstance[config.loadingId];
  }
};

/**
 * 成功处理
 * @param showSuccess
 */
const successHandler = showSuccess => {
  if (showSuccess) {
    let messageText = "操作成功";
    if (typeof showSuccess == "string") {
      messageText = showSuccess;
    }
    toast.success(messageText);
  }
};

/**
 * 异常处理
 * config : {
 *   showError 是否显示异常信息
 * }
 * @returns
 */
const errorHandler = ({ message, config, code, data }) => {
  let messageText = message || "Error";
  if (/502/.test(messageText)) {
    //后台服务重启中
    messageText = "系统服务升级中，请稍后重试";
  }
  let { showError } = config;
  if (showError && message != "skipError") {
    toast.error({
      message: messageText,
      autoClose: isNaN(parseInt(showError)) ? 3000 : parseInt(showError)
    });
  }
  return Promise.reject({
    message: messageText,
    code,
    data,
    toString() {
      return messageText;
    }
  });
};

/**
 * 生成loading 实例，唯一Id
 * @returns
 */
const getLoadingId = () => {
  let uuid = Math.random().toString(36).substring(2);
  if (mapLoadingInstance[uuid]) {
    //已存在，重新生成
    return getLoadingId();
  } else {
    return uuid;
  }
};

/** 创建请求实例 */
function createService() {
  // 创建一个 axios 实例命名为 service
  const service = axios.create({
    baseURL: window.parent.BASEURL || window.BASEURL || '/api'
  });
  // 请求拦截
  service.interceptors.request.use(
    config => {
      if (!config.url) {
        //未传入url地址，本系统默认使用 
        config.url = "/electronicSeal/signatureService";
      } else if (!/^\/api/.test(config.url as string)) {
        //config.url 不是以 "/api" 开头的话，补上默认的"/api"，但也可以请求不同的服务地址
        config.url = (import.meta.env.VITE_APP_BASE_API + config.url).replace("/api/api", "/api");
      }
      return config;
    },
    // 发送失败
    error => Promise.reject(error)
  );
  // 响应拦截（可根据具体业务作出相应的调整）
  service.interceptors.response.use(
    response => {
      // apiData 是 api 返回的数据
      let config = response.config as MyAxiosResponse;

      hideLoading(config);

      const apiData = response.data;
      // 二进制数据则直接返回
      const responseType = response.request?.responseType;
      if (["blob", "arraybuffer"].includes(responseType)) {
        return response;
      } else if (["string"].includes(typeof apiData)) {
        //聊天，返回流格式
        return apiData;
      }

      // 这个 code 是和后端约定的业务 code
      const { code, msg, message, status, data } = apiData;

      // 如果没有 code, 代表这不是项目后端开发的 api
      if (code === undefined) {
        toast.error("非本系统的接口");
        return Promise.reject(new Error("非本系统的接口"));
      }

      if (code == 0) {
        // 本系统采用 code === 0 来表示没有业务错误
        successHandler(config.showSuccess);
        //返回结构体里有token时，统一处理
        if (apiData.data.token) {
          sessionStorage.setItem("token", apiData.data.token)
        }
        return apiData.data || {};
      } else if (code == 1007) {
        // Token 过期时
        // return logout();
        return errorHandler({ message: message || msg, config, code, data });
      } else {
        // 不是正确的 code
        return errorHandler({ message: message || msg, config, code, data });
      }
    },
    error => {
      // status 是 HTTP 状态码
      let config = error.config;
      hideLoading(config);
      console.log("error.code", error.code);
      let code = error.response?.status;

      // if (code == 401) {
      //   // Token 过期时
      //   return logout();
      // }

      let message = error.response?.data.message;
      return errorHandler({
        message: message || error.message,
        config,
        code: error.code,
        data: error.data
      });
    }
  );
  return service;
}

/** 创建请求方法 */
function createRequest(service: AxiosInstance) {
  return function <T>(config: MyAxiosRequestConfig): Promise<[AxiosError, T]> {
    let defaults: MyConfig = {
      showError: true, //默认显示异常
      showSuccess: false,
      showLoading: false
    };
    config = { ...defaults, ...config };
    const token = ss.get("token");
    const defaultConfig = {
      headers: {
        // 携带 Token
        Authorization: "Bearer " + token,
        "Content-Type": "application/json",
        "version": "V1.0.0"
      },
      timeout: 60 * 1000, // 请求超时时间 1000=1s
      // baseURL: import.meta.env.VITE_APP_BASE_API,
      data: {}
    };
    // 将默认配置 defaultConfig 和传入的自定义配置 config 进行合并成为 mergeConfig
    const mergeConfig = merge(defaultConfig, config);
    let { showLoading, showLoadingText = "" } = config;
    if (showLoading) {
      let el;
      if (typeof showLoading == "boolean") {
        el = "body";
      } else if (showLoading instanceof Element) {
        el = showLoading;
      } else if ("table" == showLoading) {
        el = document.querySelectorAll(".compo-tableWithPager")[0] || document.querySelectorAll(".compo-table")[0];
      } else {
        //css选择器
        el = showLoading;
      }

      if (el) {
        let loadingId = getLoadingId();
        mergeConfig.loadingId = loadingId;
        mapLoadingInstance[loadingId] = ElLoading.service({
          target: el,
          text: showLoadingText
        });
      }
    }
    return awaitTo(service(mergeConfig)) as any;
  };
}

/** 用于网络请求的实例 */
const service = createService();
/** 用于网络请求的方法 */
// export const http = createRequest(service);
const instance = createRequest(service);

export const http = {
  get<T = any>(options: MyAxiosRequestConfig) {
    let { data } = options;

    delete options.data; //axios get请求用到的参数字段是params
    return instance<T>({
      ...options,
      params: {
        ...data
      },
      method: "get"
    });
  },
  post<T = any>(options: MyAxiosRequestConfig) {
    let { data } = options;
    let formData = new FormData();
    let paramsInHeader = {};
    for (let key in data) {
      let fieldValue = data[key];
      if (Array.isArray(fieldValue) && fieldValue[0] instanceof File) {
        //单文件上传
        formData.append(key, data[key][0]);
      } else {
        formData.append(key, data[key]);
      }
      if (key == 'businessData') {
        if (window.env == 'development') {
          for (let keyChild in fieldValue) {
            let valueChild = fieldValue[keyChild];
            formData.append('businessData_' + keyChild, valueChild)
          }
        }
        formData.set(key, JSON.stringify(fieldValue));
      }

      if (['serviceCode', 'featureCode'].includes(key)) {
        paramsInHeader[key] = fieldValue;
        if (window.env == 'development') {

        } else {
          formData.delete(key);
        }
      }

    }
    return instance<T>({
      ...options,
      method: "post",
      data: formData,
      headers: {
        ...paramsInHeader,
        ...options.headers,
        "content-type": "multipart/form-data"
      }
    });
  },
  put<T = any>(options: MyAxiosRequestConfig) {
    return instance<T>({
      ...options,
      method: "put"
    });
  },
  delete<T = any>(options: MyAxiosRequestConfig) {
    let { data } = options;
    delete options.data; //axios get请求用到的参数字段是params
    return instance<T>({
      ...options,
      // params: {
      //   ...data
      // },
      data: data,
      method: "delete"
    });
  },
  /**
   * 文件上传
   * @param options
   * @param isMultiple  boolean 是否为多文件上传，默认false
   * @returns
   */
  upload<T = any>(options: MyAxiosRequestConfig, isMultiple = false) {
    let { data } = options;
    let formData = new FormData();
    for (let key in data) {
      let fieldValue = data[key];
      if (Array.isArray(fieldValue) && fieldValue[0] instanceof File) {
        if (isMultiple) {
          data[key].forEach((item, index) => {
            formData.append(key + `[${index}]`, item);
          });
        } else {
          //单文件上传
          formData.append(key, data[key][0]);
        }
      } else {
        formData.append(key, data[key]);
      }
    }

    // console.log("formData", formData);

    return instance<T>({
      ...options,
      method: "post",
      data: formData,
      headers: {
        "content-type": "multipart/form-data"
      }
    });
  },
  hideLoading
};
